package com.alex.space.commons.jdk.kit8;

import scala.Int;

import java.lang.annotation.*;
import java.nio.charset.StandardCharsets;
import java.time.*;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Alex
 * Created by Alex on 2018/4/9.
 */
public class Kit8_Feature {
	private static List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

	public static void main(String[] args) {
		testLambda();

		testStream();

		testDefaultFunctionInterface();

		testMethodReference();

		testRepeatingAnnotations();

		testElementType();

		testDateTime();

		testBase64();

		testParallel();
	}

	private static void testLambda() {
		list.forEach(System.out::println);

		list.forEach(e -> System.out.println("data " + e));
	}

	private static void testStream() {
		List<Integer> nums = Arrays.asList(1, 2, 3, null, 5, 6, 3, 8, 9, null, 6, 10);
		System.out.println("Sum" +
				nums
						.stream()
						.filter(Objects::nonNull)
						.distinct()
						.mapToInt(x -> x * 2)
						.skip(1)
						.limit(3)
						.peek(System.out::println)
						.sum()
		);

		Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5))
				.forEach(integer -> System.out.print(integer + "  "));

		List<Integer> collectList = Stream.of(1, 2, 3, 4)
				.collect(Collectors.toList());
		System.out.println("collectList: " + collectList);

		Set<Integer> collectSet = Stream.of(1, 2, 3, 4)
				.collect(Collectors.toSet());
		System.out.println("collectSet: " + collectSet);

		Map<Integer, Integer> map = Stream.of(1, 2, 3, 4)
				.collect(Collectors.toMap(x -> x * 2, y -> y + 1));
		System.out.println("collectMap: " + map);

		Map<Boolean, List<Integer>> collects = Stream.of(1, 2, 3, 4)
				.collect(Collectors.partitioningBy(it -> it % 2 == 0));
		System.out.println("collectPartition : " + collects);

		Map<Boolean, List<Integer>> collectGroup = Stream.of(1, 2, 3, 4)
				.collect(Collectors.groupingBy(it -> it > 3));
		System.out.println("collectGroup : " + collectGroup);

		Optional accResult = Stream.of(1, 2, 3, 4)
				.reduce((a1, a2) -> {
					System.out.println("a1 : " + a1);
					a1 += a2;
					System.out.println("item: " + a2);
					System.out.println("a1+ : " + a1);
					System.out.println("--------");
					return a1;
				});
		System.out.println("accResult: " + accResult.get());

		int accResult2 = Stream.of(1, 2, 3, 4)
				.reduce(5, (acc, item) -> {
					System.out.println("acc : " + acc);
					acc += item;
					System.out.println("item: " + item);
					System.out.println("acc+ : " + acc);
					System.out.println("--------");
					return acc;
				});
		System.out.println("accResult: " + accResult2);

		ArrayList<Integer> accResult_ = Stream.of(1, 2, 3, 4)
				.reduce(new ArrayList<Integer>(),
						new BiFunction<ArrayList<Integer>, Integer, ArrayList<Integer>>() {
							@Override
							public ArrayList<Integer> apply(ArrayList<Integer> acc, Integer item) {

								acc.add(item);
								System.out.println("item1: " + item);
								System.out.println("acc1+ : " + acc);
								System.out.println("BiFunction");
								return acc;
							}
						}, new BinaryOperator<ArrayList<Integer>>() {
							@Override
							public ArrayList<Integer> apply(ArrayList<Integer> acc, ArrayList<Integer> item) {
								System.out.println("BinaryOperator");
								acc.addAll(item);
								System.out.println("item2: " + item);
								System.out.println("acc2+ : " + acc);
								System.out.println("--------");
								return acc;
							}
						});
		System.out.println("accResult_: " + accResult_);
	}

	private static void testDefaultFunctionInterface() {
		// 可以直接使用接口名.静态方法来访问接口中的静态方法
		JDK8Interface1.staticMethod();
		// 接口中的默认方法必须通过它的实现类来调用
		new Kit8_Feature().new JDK8InterfaceImpl1().defaultMethod();
		// 多实现类，默认方法重名时必须复写
		new Kit8_Feature().new JDK8InterfaceImpl2().defaultMethod();
	}

	private static void testMethodReference() {
		//构造器引用。语法是Class::new，或者更一般的Class< T >::new，要求构造器方法是没有参数；
		final Car car = Car.create(Car::new);
		final List<Car> cars = Arrays.asList(car);
		//静态方法引用。语法是Class::static_method，要求接受一个Class类型的参数；
		cars.forEach(Car::collide);
		//任意对象的方法引用。它的语法是Class::method。无参，所有元素调用；
		cars.forEach(Car::repair);
		//特定对象的方法引用，它的语法是instance::method。有参，在某个对象上调用方法，将列表元素作为参数传入；
		final Car police = Car.create(Car::new);
		cars.forEach(police::follow);
	}

	private static void testRepeatingAnnotations() {
		RepeatingAnnotations.main(null);
	}

	private static void testElementType() {
		Annotations.main(null);
	}

	private static void testDateTime() {
		final Clock clock = Clock.systemUTC();
		System.out.println(clock.instant());
		System.out.println(clock.millis());

		final LocalDate date = LocalDate.now();
		System.out.println(date);

		final LocalTime time = LocalTime.now();
		System.out.println(time);

		final LocalDateTime datetime = LocalDateTime.now();
		System.out.println(datetime);

		final ZonedDateTime zonedDatetime = ZonedDateTime.now();
		final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now(clock);
		final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now(ZoneId.of("America/Los_Angeles"));

		System.out.println(zonedDatetime);
		System.out.println(zonedDatetimeFromClock);
		System.out.println(zonedDatetimeFromZone);

		final LocalDateTime from = LocalDateTime.of(2014, Month.APRIL, 16, 0, 0, 0);
		final LocalDateTime to = LocalDateTime.of(2015, Month.APRIL, 16, 23, 59, 59);
		final Duration duration = Duration.between(from, to);
		System.out.println("Duration in days: " + duration.toDays());
		System.out.println("Duration in hours: " + duration.toHours());


	}

	private static void testBase64() {
		final String text = "就是要测试加解密！！abjdkhdkuasu!!@@@@";
		String encoded = Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8));

		System.out.println("加密后=" + encoded);

		String decoded = new String(Base64.getDecoder().decode(encoded), StandardCharsets.UTF_8);
		System.out.println("解密后=" + decoded);
	}

	private static void testParallel() {
		long[] arrayOfLong = new long[20000];
		Arrays.parallelSetAll(arrayOfLong, idx -> ThreadLocalRandom.current().nextInt(100000));

		Arrays.stream(arrayOfLong).limit(10).forEach(System.out::println);

		Arrays.parallelSort( arrayOfLong );
	}


	public interface JDK8Interface1 {

		/**
		 * 1.接口中可以定义静态方法了
		 */
		public static void staticMethod() {
			System.out.println("接口中的静态方法");
		}

		/**
		 * 2.使用default之后就可以定义普通方法的方法体了
		 */
		public default void defaultMethod() {
			System.out.println("接口中的默认方法");
		}
	}

	public class JDK8InterfaceImpl1 implements JDK8Interface1 {
		public void test() {

		}
	}

	public interface JDK8Interface2 {

		//接口中可以定义静态方法了
		public static void staticMethod() {
			System.out.println("接口中的静态方法");
		}

		//使用default之后就可以定义普通方法的方法体了
		public default void defaultMethod() {
			System.out.println("接口中的默认方法");
		}
	}

	public class JDK8InterfaceImpl2 implements JDK8Interface1, JDK8Interface2 {

		@Override
		public void defaultMethod() {
			System.out.println("实现类复写重名默认方法！！！！");
		}
	}

	public static class Car {
		public static Car create(final Supplier<Car> supplier) {
			return supplier.get();
		}

		public static void collide(final Car car) {
			System.out.println("静态方法引用 " + car.toString());
		}

		public void repair() {
			System.out.println("任意对象的方法引用 " + this.toString());
		}

		public void follow(final Car car) {
			System.out.println("特定对象的方法引用 " + car.toString());
		}
	}

	public static class RepeatingAnnotations {
		@Target(ElementType.TYPE)
		@Retention(RetentionPolicy.RUNTIME)
		public @interface Filters {
			Filter[] value();
		}

		// 重复注解
		@Target(ElementType.TYPE)
		@Retention(RetentionPolicy.RUNTIME)
		@Repeatable(Filters.class)
		public @interface Filter {
			String value();

			String value2();
		}

		@Filter(value = "filter1", value2 = "111")
		@Filter(value = "filter2", value2 = "222")
		public interface Filterable {
		}

		public static void main(String[] args) {
			//获取注解后遍历打印值
			for (Filter filter : Filterable.class.getAnnotationsByType(Filter.class)) {
				System.out.println(filter.value() + filter.value2());
			}
		}


	}

	/**
	 * 新增类型注解:ElementType.TYPE_USE 和ElementType.TYPE_PARAMETER
	 */
	public static class Annotations {
		@Retention(RetentionPolicy.RUNTIME)
		@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
		public @interface NonEmpty {
		}

		public static class Holder<@NonEmpty T> extends @NonEmpty Object {
			public void method() throws @NonEmpty Exception {
			}
		}

		public static void main(String[] args) {
			final Holder<String> holder = new @NonEmpty Holder<String>();
			@NonEmpty Collection<@NonEmpty String> strings = new ArrayList<>();
		}

	}


}
